﻿#include "stdafx.h"
#include "AdslMgr.h"

/*
Modify By CcTry.CoM
*/

CAdslMgr::CAdslMgr()
{
}

CAdslMgr::~CAdslMgr()
{
}

VOID WINAPI RasDialFunc(UINT unMsg, RASCONNSTATE rasconnstate, DWORD dwError)
{
	CString str;
	switch (rasconnstate)
	{
	case RASCS_OpenPort:
		str = "正在打开端口...";
		break;

	case RASCS_PortOpened:
		str = "端口已经打开";
		break;

	case RASCS_ConnectDevice:
		str = "在正连接设备";
		break;

	case RASCS_DeviceConnected:
		str = "设备已经连接上";
		break;

	case RASCS_AllDevicesConnected:
		str = "所有设备已经连接上";
		break;

	case RASCS_Authenticate:
		str = "正在验证用户名和密码...";
		break;

	case RASCS_AuthNotify:
		str = "IDS_RASCS_7";
		break;

	case RASCS_AuthRetry:
		str = "再次验证用户名和密码...";
		break;

	case RASCS_AuthCallback:
		str = "回收验证";
		break;

	case RASCS_AuthChangePassword:
		str = "改变密码请求";
		break;

	case RASCS_AuthProject:
		str = "开始连接状态";
		break;

	case RASCS_AuthLinkSpeed:
		str = "计算连接速度...";
		break;

	case RASCS_AuthAck:
		str = "Authentication Acknowledged";
		break;

	case RASCS_ReAuthenticate:
		str = "Reauthenticatation Started";
		break;

	case RASCS_Authenticated:
		str = "Authenticated";
		break;

	case RASCS_PrepareForCallback:
		str = "Preparation For Callback";
		break;

	case RASCS_WaitForModemReset:
		str = "等待设备重置...";
		break;

	case RASCS_WaitForCallback:
		str = "Waiting For Callback";
		break;

	case RASCS_Interactive:
		str = "Interactive";
		break;

	case RASCS_RetryAuthentication:
		str = "再次验证";
		break;

	case RASCS_CallbackSetByCaller:
		str = "Callback Set By Caller";
		break;

	case RASCS_PasswordExpired:
		str = "密码过期";
		break;

	case RASCS_Connected:
		str = "拨号已经连接";
		break;

	case RASCS_Disconnected:
		str = "已经断开连接";
		break;

	default:
		str = "未定义的错误代码";
		break;
	}
}

BOOL CAdslMgr::IsConnected()
{
	BOOL bRet = FALSE;
	LPRASCONN lpRasConn = NULL;
	DWORD dwCb = 0, dwConnections = 0;
	HRASCONN hrasconn;
	RASCONNSTATUS rasStatus;

	DWORD dwRet = RasEnumConnections(lpRasConn, &dwCb, &dwConnections);
	if (dwRet == ERROR_BUFFER_TOO_SMALL)
	{
		lpRasConn = (LPRASCONN)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCb);
		if (!lpRasConn) return FALSE;

		lpRasConn[0].dwSize = sizeof(RASCONN);
		dwRet = RasEnumConnections(lpRasConn, &dwCb, &dwConnections);

		if (ERROR_SUCCESS != dwRet)
		{
			HeapFree(GetProcessHeap(), 0, lpRasConn);
			return FALSE;
		}
	}

	for (DWORD idx = 0; idx < dwConnections; ++idx)
	{
		if (m_strPPPoEName.CompareNoCase(lpRasConn[idx].szEntryName) == 0)
		{
			hrasconn = lpRasConn[idx].hrasconn;
			rasStatus.dwSize = sizeof(RASCONNSTATUS);
			dwRet = RasGetConnectStatus(hrasconn, &rasStatus);
			if (ERROR_SUCCESS != dwRet || rasStatus.rasconnstate != RASCS_Connected)
			{
				bRet = FALSE;
			}

			bRet = TRUE;
			break;
		}
	}

	if (lpRasConn)
	{
		HeapFree(GetProcessHeap(), 0, lpRasConn);
		lpRasConn = NULL;
	}

	return bRet;
}


//http://ideone.com/aiNBtJ
BOOL CAdslMgr::CreatePPPoE(CString strEntryName, CString strUser, CString strPass)
{
	if (strEntryName.IsEmpty()) strEntryName = RASDT_PPPoE;

	LPRASENTRY lpRasEntry = NULL;
	DWORD cb = sizeof(RASENTRY);
	DWORD dwBufferSize = 0;

	DWORD dwRet = RasGetEntryProperties(NULL, _T(""), NULL, &dwBufferSize, NULL, NULL);
	if (ERROR_BUFFER_TOO_SMALL != dwRet || dwBufferSize <= 0) return FALSE;

	lpRasEntry = (LPRASENTRY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
	if (!lpRasEntry) return FALSE;

	ZeroMemory(lpRasEntry, sizeof(RASENTRY));
	lpRasEntry->dwSize = dwBufferSize;

	lpRasEntry->dwfOptions = RASEO_PreviewUserPw | RASEO_ModemLights | RASEO_RemoteDefaultGateway | RASEO_SwCompression | RASEO_RequirePAP | RASEO_RequireSPAP |
		RASEO_RequireCHAP | RASEO_RequireMsCHAP | RASEO_RequireMsCHAP2 | RASEO_SecureLocalFiles;
	lpRasEntry->dwfOptions2 = RASEO2_Internet | RASEO2_DontNegotiateMultilink | RASEO2_ReconnectIfDropped;
	lpRasEntry->dwIdleDisconnectSeconds = RASIDS_Disabled;
	lpRasEntry->dwfNetProtocols = RASNP_Ip;
	lpRasEntry->dwFramingProtocol = RASFP_Ppp;
	lpRasEntry->dwType = RASET_Broadband;
	lpRasEntry->dwEncryptionType = ET_Optional;
	lpRasEntry->dwDialMode = RASEDM_DialAll;
	lpRasEntry->dwRedialCount = 3;
	lpRasEntry->dwRedialPause = 60;
	_tcscpy_s(lpRasEntry->szDeviceType, RASDT_PPPoE);
	_tcscpy_s(lpRasEntry->szDeviceName, _T("PPPoE"));

	dwRet = RasSetEntryProperties(NULL, strEntryName, lpRasEntry, dwBufferSize, NULL, 0); // 创建连接
	HeapFree(GetProcessHeap(), 0, (LPVOID)lpRasEntry);
	if (dwRet != ERROR_SUCCESS) return FALSE;

	m_strPPPoEName = strEntryName;

	if (strUser.GetLength() > 0 && strPass.GetLength() > 0)
	{
		//为拨号连接保存用户名密码
		RASCREDENTIALS RS_cred;
		memset(&RS_cred, 0, sizeof(RASCREDENTIALS));
		RS_cred.dwSize = sizeof(RS_cred);
		RS_cred.dwMask = RASCM_UserName | RASCM_Password | RASCM_DefaultCreds;
		_tcscpy_s(RS_cred.szUserName, strUser);
		_tcscpy_s(RS_cred.szPassword, strPass);
		dwRet = RasSetCredentials(NULL, strEntryName, &RS_cred, FALSE);

		RASDIALPARAMS rdParams = { 0 };
		rdParams.dwSize = sizeof(RASDIALPARAMS);
		_tcscpy_s(rdParams.szEntryName, strEntryName);
		_tcscpy_s(rdParams.szUserName, strUser);
		_tcscpy_s(rdParams.szPassword, strPass);

		dwRet = RasSetEntryDialParams(NULL, &rdParams, FALSE);
		if (dwRet == ERROR_SUCCESS) return TRUE;

#if (WINVER >= 0x601)
		if (dwRet == ERROR_INVALID_SIZE)
		{
			rdParams.dwSize = offsetof(RASDIALPARAMSW, dwIfIndex);
			dwRet = RasSetEntryDialParams(NULL, &rdParams, FALSE);
		}
#elif (WINVER >= 0x401)
		if (dwRet == ERROR_INVALID_SIZE)
		{
			rdParams.dwSize = offsetof(RASDIALPARAMSW, dwSubEntry);
			dwRet = RasSetEntryDialParams(NULL, &rdParams, FALSE);
		}
#endif
	}

	return TRUE;
}

BOOL CAdslMgr::OnEnum(CString strPPPoEName)
{
	if (strPPPoEName.IsEmpty()) return FALSE;

	RASENTRYNAME Entries[MAX_ENTRY_LEN] = { 0 };
	DWORD cbb = sizeof(Entries), cEntries = 0;
	Entries[0].dwSize = sizeof(RASENTRYNAME);

	DWORD dwRets = RasEnumEntries(NULL, NULL, Entries, &cbb, &cEntries);  //如果函数成功，则返回0
	if (dwRets != ERROR_SUCCESS || cEntries <= 0) return FALSE;

	for (DWORD idx = 0; idx < cEntries; ++idx)
	{
		if (strPPPoEName.CompareNoCase(Entries[idx].szEntryName) == 0)
		{
			m_strPPPoEName = strPPPoEName;
			return TRUE;
		}
	}

	return FALSE;
}

//#include "WinHttpEx.h"
BOOL CAdslMgr::GetIpAddrByRemote(CString& strIp)
{
	//CString strContent, strAddress;
	//CString strUrl = _T("http://ip.chinaz.com/getip.aspx");

	//CWinHttpEx winHttp;
	//BOOL bRet = winHttp.GetUrlContentString(strUrl, strContent, NULL, HTTP_HEADER_JOIN_CURR, TRUE);
	//if (!bRet || winHttp.GetHttpStatusCode() != 200 || strContent.IsEmpty())
	//{
	//	return FALSE;
	//}

	//strIp = winHttp.GetContentSubString(_T("ip:\'"), _T("\'"));
	//if (strIp.IsEmpty()) return FALSE;

	return TRUE;
}

BOOL CAdslMgr::ChangeIpAddr(CString strPPPoEName, CString strUser, CString strPass)
{
	if (strPPPoEName.IsEmpty()) strPPPoEName = RASDT_PPPoE;
	m_strPPPoEName = strPPPoEName;

	BOOL bRet = FALSE;
	if (m_IpMap.IsEmpty())
	{
		CString strIp;
		bRet = GetIpAddrByRemote(strIp);
		if (bRet)
		{
			m_IpMap.SetAt(strIp, strIp);
		}
	}

	do
	{
		RAS_Close(FALSE);
		Sleep(2 * 1000);

		bRet = OnEnum(strPPPoEName);
		if (!bRet)
		{
			bRet = CreatePPPoE(strPPPoEName, strUser, strPass);
			if (!bRet) return FALSE;
		}

		CString strIpAddr;
		bRet = RAS_Connect(strUser, strPass, &strIpAddr);
		if (!bRet) return FALSE;

		bRet = IsConnected();
		if (!bRet) return FALSE;

		CString strValue;
		bRet = m_IpMap.Lookup(strIpAddr, strValue);
		if (!bRet)
		{
			m_IpMap.SetAt(strIpAddr, strIpAddr);
			break;
		}
		else
		{
			Sleep(3 * 1000);
			continue;
		}

	} while (TRUE);

	return TRUE;
}

BOOL CAdslMgr::RAS_Connect(CString strUser, CString strPass, CString *pOutIpAddr)
{
	HRASCONN hRasConn = NULL;
	CString strEntryName = m_strPPPoEName;

	RASDIALPARAMS rdParams;							//拨号连接的信息
	ZeroMemory(&rdParams, sizeof(RASDIALPARAMS));
	rdParams.dwSize = sizeof(RASDIALPARAMS);
	_tcscpy_s(rdParams.szEntryName, L"xg42");
	_tcscpy_s(rdParams.szUserName, L"xg42");
	_tcscpy_s(rdParams.szPassword, L"123");

	DWORD dwRet = RasDial(NULL, NULL, &rdParams, 0L, /*RasDialFunc*/NULL, &hRasConn);  //如果函数成功，则返回0
	if (dwRet != ERROR_SUCCESS && dwRet != ERROR_INVALID_SIZE) return FALSE;

	if (dwRet == ERROR_INVALID_SIZE)
	{
#if (WINVER >= 0x601)
		rdParams.dwSize = offsetof(RASDIALPARAMSW, dwIfIndex);
		dwRet = RasDial(NULL, NULL, &rdParams, 0L, /*RasDialFunc*/NULL, &hRasConn);
#elif (WINVER >= 0x401)
		rdParams.dwSize = offsetof(RASDIALPARAMSW, dwSubEntry);
		dwRet = RasDial(NULL, NULL, &rdParams, 0L, /*RasDialFunc*/NULL, &hRasConn);
#endif
	}
	if (dwRet != ERROR_SUCCESS) return FALSE;

	RASCONNSTATUS rStatus;
	dwRet = RasGetConnectStatus(hRasConn, &rStatus);
	if (ERROR_SUCCESS != dwRet || rStatus.rasconnstate != RASCS_Connected) return FALSE;

	//----------------------- 获取拨号连接的IP地址
	RASPPPIP raspppip = { 0 };
	raspppip.dwSize = sizeof(RASPPPIP);
	DWORD cb = sizeof(RASPPPIP);
	RasGetProjectionInfo(hRasConn, RASP_PppIp, &raspppip, &cb);

	if (pOutIpAddr)
	{
		*pOutIpAddr = raspppip.szIpAddress;
	}

	return TRUE;
}


CString CAdslMgr::CheckNet()
{
	DWORD dwFlag;
	if (!InternetGetConnectedState(&dwFlag, 0))
	{
		return _T("未连接到网络");
	}
	else if (dwFlag & INTERNET_CONNECTION_MODEM)
	{
		return _T("上网类型：采用RAS拨号连接上网");
	}
	else  if (dwFlag & INTERNET_CONNECTION_LAN)
	{
		return _T("上网类型：采用网卡通过局域网上网");
	}
	else if (dwFlag & INTERNET_CONNECTION_PROXY)
	{
		return _T("上网类型：使用代理服务器上网");
	}

	return _T("未知网络类型");
}

void CAdslMgr::RAS_Close(BOOL bCloseAll)
{
	RASCONN ras[MAX_ENTRY_LEN] = { 0 };
	DWORD dwSize = 0, dwNumber = 0;
	ras[0].dwSize = sizeof(RASCONN);
	dwSize = sizeof(ras);
	DWORD dwRet = RasEnumConnections(ras, &dwSize, &dwNumber);
	if (dwRet != ERROR_SUCCESS || dwNumber <= 0) return;

	for (DWORD dwIdx = 0; dwIdx < dwNumber; dwIdx++)
	{
		if (bCloseAll)
		{
			dwRet = RasHangUp(ras[dwIdx].hrasconn);
		}
		else if (m_strPPPoEName.CompareNoCase(ras[dwIdx].szEntryName) == 0)
		{
			dwRet = RasHangUp(ras[dwIdx].hrasconn);
			break;
		}
	}
}